//Includes
#include "stdafx.h"
#include "Game.h"
#include "Camera.h"
#include "ObjectManager.h"
#include "Bullets.h"
#include "Player.h"
#include "Gun.h"

//Open Gl
#include <gl/gl.h>
#include <gl/glu.h>
#include <iostream>
#include <fstream>
using namespace std;

CGame* CGame::m_pInstance = NULL;

CGame* CGame::GetInstance(void)
{
	if(!m_pInstance)
		m_pInstance = new CGame();

	return m_pInstance;
}

void CGame::GameInit()
{
	//Base Variables
	this->m_vTranslation.make_zero();
	this->m_pMyCam = CCamera::GetInstance();
	this->m_pMyCam->CameraInit();
	this->m_vPreviousPos = m_pMyCam->GetOrigin();

	this->m_nScreenHeight = -1;
	this->m_nScreenWidth  = -1;

	this->m_vWorldY.make_zero();
	this->m_vWorldY.y = 1.0f;

	//Set all buffered keys to true
	for(int i = 0; i < 16; ++i)
	{
		this->m_bBuffKeysUp[i] = true;
	}

	//OBJ Manager
	this->m_pOBJManager = COBJManager::GetInstance();
	this->m_pOBJManager->CreateObjects();

	//Lighting
	this->SetUpLighting();

	//Matrix Mode
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();

	//Player
	this->m_pPlayer = CPlayer::GetInstance();
	this->m_pPlayer->PlayerInit();
	this->m_pPlayer->GetPlayerMat()->make_identity();
	this->m_pPlayer->SetForward(this->m_pMyCam->GetForward());
	this->m_pPlayer->SetOrigin(this->m_pMyCam->GetOrigin());

	this->m_pGun = new CGun();
	this->m_pGun->Init();

	//DEBUG ONLY
	this->m_vPlayerPos = this->m_pMyCam->GetOrigin();
	this->m_vPlayerPos.y = 1.0f;
	this->m_bFirstPerson = true;
	this->m_pPlayerCylinder = new Cylinder();
	this->m_pPlayerCylinder->Create(m_vPlayerPos, 1.0f, 0.5f, 32, 32);
	this->m_bSwitchViewKeyDown = false;

	//Testing
	this->m_pPlayer->SetOrigin(m_vPlayerPos);
	this->m_pMyCam->SetOrigin(m_vPlayerPos);
}

void CGame::Input(float fDeltaTime)
{
	//Changing View - DEBUG ONLY
	if(GetAsyncKeyState(VK_F1))
	{
		if(m_bSwitchViewKeyDown == false)
		{
			m_bSwitchViewKeyDown = true;
			m_bFirstPerson = !m_bFirstPerson;
			
			if(m_bFirstPerson)
			{
				m_pMyCam->SetOrigin(m_pPlayer->GetPlayerPosition());
				m_pMyCam->SetAxes(m_vWorldY, m_pPlayer->GetPlayerMat()->axis_z);
			}
		}
	}

	else
	{
		m_bSwitchViewKeyDown = false;
	}


	//Keyboard
	if(GetAsyncKeyState('A'))
	{
		this->m_vTranslation.x += 6.0f*fDeltaTime;
	}

	if(GetAsyncKeyState('D'))
	{
		this->m_vTranslation.x -= 6.0f*fDeltaTime;
	}

	if(GetAsyncKeyState('W'))
	{
		this->m_vTranslation.z += 6.0f*fDeltaTime;
	}

	if(GetAsyncKeyState('S'))
	{
		this->m_vTranslation.z -= 6.0f*fDeltaTime;
	}

	//TODO: Mouse look
	if(GetAsyncKeyState(VK_RBUTTON))
	{
		this->MouseLook(2*fDeltaTime);
	}

	if(m_bFirstPerson)
	{
		if(GetAsyncKeyState(VK_LBUTTON))
		{
			if(this->m_pGun->Shoot())
			{
				this->Shoot();
			}
		}
	}

	if(GetAsyncKeyState(VK_SPACE))
	{
		if(this->m_pPlayer->GetRecharging() == false)
		{
			this->m_pPlayer->SetJumping(true);
		}

		else
		{
			m_pPlayer->SetJumping(false);
		}
	}

	else
	{
		this->m_pPlayer->SetJumping(false);
	}
}

void CGame::Update(float fDeltaTime)
{
	//Update Gun
	this->m_pGun->Update(fDeltaTime);

	//Reset any needed values
	this->m_vTranslation.make_zero();
	this->Input(fDeltaTime);

	if(m_bFirstPerson)
	{
		this->m_vPreviousPos = m_pPlayer->GetPlayerPosition();
		this->m_pPlayer->TranslatePlayer(m_vTranslation);
		this->m_pMyCam->SetOrigin(m_pPlayer->GetPlayerPosition());
		this->m_pMyCam->SetYValue(m_pMyCam->GetOrigin().y + 0.5f);
	}

	else
	{
		//Third person
		this->m_pMyCam->TranslateCamera(m_vTranslation);
	}

	this->m_pPlayer->Update(fDeltaTime);

	//Update Objects
	this->m_pOBJManager->Update(fDeltaTime);
}

void CGame::Render()
{	
	//Debug only
	vec3f temp = this->m_pPlayer->GetPlayerPosition();
	GLfloat pos[] = {temp.x, temp.y, temp.z, 1.0f};
	glLightfv(GL_LIGHT0, GL_POSITION, pos);

	glPushMatrix();
	{
		m_pMyCam->ApplyTransform();

		//Draw Ground
		this->DrawGround();
		glColor3f(0.5f, 0.5f, 0.5f);
		this->m_pOBJManager->Render();
	}
	glPopMatrix();

	if(!m_bFirstPerson)
	{
		//Draw a cylinder where player should be
		glPushMatrix();
		{
			glDisable(GL_CULL_FACE);
			m_pMyCam->ApplyTransform();
			glTranslatef(m_vPlayerPos.x, m_vPlayerPos.y, m_vPlayerPos.z);
			glRotatef(-90.0f, 1.0f, 0.0f, 0.0f);
			glColor3f(1.0f, 0.0f, 0.0f);
			m_pPlayerCylinder->Render();
			glEnable(GL_CULL_FACE);
		}
		glPopMatrix();
	}

	//Render hud
	this->RenderHUD();
}

void CGame::DrawGround()
{
	//Draw ground
	glColor3f(0.0f, 1.0f, 0.0f);
	glBegin(GL_LINES);
	{
		for (float i = 0.0f; i < 101; ++i)
		{
			//X alligned lines
			glVertex3f(i, 0, 0);
			glVertex3f(i, 0, 100.0f);

			//Z alligned Lines
			glVertex3f(0, 0, i);
			glVertex3f(100.0f, 0, i);
		}
	}
	glEnd();	
}

void CGame::MouseLook(float fDeltaTime)
{ 
	//Clear out our matrix
	this->m_vTempMat.make_identity();

	this->m_vTempMat = this->m_pMyCam->MakeMatrix();

	// Get the location of the cursor
	POINT mousePos;
	GetCursorPos( &mousePos );

	// Set the location to 400 300 in the window
	SetCursorPos(this->m_nScreenWidth/2, this->m_nScreenHeight/2);

	// finding how much the mouse moved
	float mouseDiff[2] = { float(this->m_nScreenWidth/2 - mousePos.x), float(mousePos.y - this->m_nScreenHeight/2) };

	//scale by an FDT for a smoother look
	mouseDiff[0] *= fDeltaTime;
	mouseDiff[1] *= fDeltaTime;

	// Rotate the camera matrix by that amount
	this->m_vTempMat.rotate_y(mouseDiff[0]);
	this->m_vTempMat.rotate_x(mouseDiff[1]);

	//reset the matrix to the new orientation
	// create three new vectors and set one to the z axis of the camera matrix
	vec3f z_vec = m_vTempMat.axis_z;
	vec3f x_vec, y_vec;

	z_vec.normalize();

	// cross the z you created with the y vector of your world to find your new X
	x_vec = cross_product(m_vWorldY, z_vec);

	//normalize the vector
	x_vec.normalize();

	// cross the z with the new x and get the new y then normalize
	y_vec = cross_product(z_vec, x_vec);
	y_vec.normalize();

	// plug the new vectors into the matrix
	//This should be orienting the camera
	this->m_pMyCam->SetAxes(y_vec, z_vec);
	this->m_pPlayer->SetAxes(y_vec, z_vec);
}

void CGame::GroundClamp(vec3f vPos)
{
	//For now, it's a level floor
	this->m_pMyCam->SetYValue(1.0f);
}
void CGame::Shoot()
{
	//Create bullet
	CBullets* b = new CBullets();
	vec3f* p; vec3f* f; p = new vec3f(); f = new vec3f();
	*p = m_pMyCam->GetOrigin();
	*f = m_pMyCam->GetForward();
	b->CreateBullet(0.125f, 5.0f, 10.0f, 0, p, f);
	//Bullet trajectory comes camera Z
	this->m_pOBJManager->m_vBullets.push_back(b);
}

void CGame::SetPlayerPos(vec3f v)
{
	m_pMyCam->SetOrigin(v);
}

void CGame::SetUpLighting()
{
	glEnable(GL_DEPTH_TEST);
	glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);

	//Setting up Lighting
	GLfloat noLight[] = {0.0f, 0.0f, 0.0f, 0.0f};
	GLfloat someLight[] = {0.3f, 0.3f, 0.3f, 0.0f};
	GLfloat fullLight[] = {1.0f, 1.0f, 1.0f, 0.0f};
	glLightModelfv(GL_LIGHT_MODEL_AMBIENT, noLight);

	glEnable(GL_LIGHT0);
	glLightfv(GL_LIGHT0, GL_AMBIENT, someLight);
	glLightfv(GL_LIGHT0, GL_DIFFUSE, fullLight);
	glLightfv(GL_LIGHT0, GL_SPECULAR, fullLight);

	glEnable(GL_COLOR_MATERIAL);
	glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);

	//Light 1
	glEnable(GL_LIGHT1);
	glLightfv(GL_LIGHT1, GL_AMBIENT, noLight);
	glLightfv(GL_LIGHT1, GL_DIFFUSE, fullLight);
	glLightfv(GL_LIGHT1, GL_SPECULAR, fullLight);
	
	glMaterialfv(GL_FRONT, GL_SPECULAR, fullLight);
	glMateriali(GL_FRONT, GL_SHININESS, 128);

	//Testing for giggles
	glLightModelfv(GL_LIGHT_MODEL_AMBIENT, fullLight);

}
void CGame::RenderHUD()
{
	glMatrixMode(GL_PROJECTION);
	glPushMatrix();
	{
		glLoadIdentity();
		gluOrtho2D(0, 600, 0, 800);
		 
		glDisable(GL_LIGHTING);
		glDisable(GL_DEPTH_TEST);

		//Transparency
		glEnable(GL_BLEND);
		glEnable(GL_TEXTURE_2D);

		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
		glColor4f(1.0f, 1.0f, 1.0f, 0.05f);

		//Draw the quad
		glBegin(GL_QUADS);
		{
			glTexCoord2f(0, 0);
			glVertex2f(0, 0);
			glTexCoord2f(1.0f, 0);
			glVertex2f(600, 0);
			glTexCoord2f(1.0f, 1.0f);
			glVertex2f(600, 800);
			glTexCoord2f(0, 1.0f);
			glVertex2f(0, 800);		
		}
		glEnd();
	}
	glPopMatrix();

	glEnable(GL_LIGHTING);
	glEnable(GL_DEPTH_TEST);
	glDisable(GL_BLEND);
	
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();

}